home *** CD-ROM | disk | FTP | other *** search
/ Acorn User: China / Acorn User China CD-ROM (UK) (Disc A) / Acorn User China CD-ROM (UK) (Disc A).bin / DEMON / MISC / NETLITE2.ARC / NET / c / TELNET < prev    next >
Encoding:
Text File  |  1993-04-10  |  13.8 KB  |  470 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "dbox.h"
  5. #include "werr.h"
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "icmp.h"
  10. #include "netuser.h"
  11. #include "tcp.h"
  12. #include "telnet.h"
  13. #include "session.h"
  14. #include "misc.h"
  15. #include "domain.h"
  16.  
  17. static int  telnet(int32, char *, char *, char *, struct session *);
  18. static int  telnet_error(char *, char *, struct session *); 
  19. static void free_telnet(struct telnet *);
  20. static void willopt(struct telnet *, char);
  21. static void wontopt(struct telnet *, char);
  22. static void doopt(struct telnet *, char);
  23. static void dontopt(struct telnet *, char);
  24. static void answer(struct telnet *, int, int); 
  25.  
  26. #define CTLZ    26
  27.  
  28. #define TELNET_Connect    0
  29. #define TELNET_Host       1
  30. #define TELNET_Port       3
  31.  
  32. extern char nospace[];
  33. extern char badhost[];
  34. int refuse_echo = 0;
  35. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  36.  
  37. #ifdef  DEBUG
  38. char *t_options[] = {
  39.         "Transmit Binary",
  40.         "Echo",
  41.         "",
  42.         "Suppress Go Ahead",
  43.         "",
  44.         "Status",
  45.         "Timing Mark"
  46. };
  47. #endif
  48.  
  49. void start_telnet(void)
  50. {
  51.         struct session *session;
  52.         char buffer[80];
  53.         char Host[256];
  54.         char Port[5];
  55.         dbox d;
  56.  
  57.         if ((d = dbox_new("TELNET")) == NULL)
  58.                  return;
  59.  
  60.         dbox_setfield(d, TELNET_Host, "");
  61.         dbox_setfield(d, TELNET_Port, "23");
  62.         dbox_show(d);
  63.  
  64.         if (dbox_fillin(d) == TELNET_Connect)
  65.         {
  66.                  dbox_getfield(d, TELNET_Host, Host, 255);
  67.                  dbox_getfield(d, TELNET_Port, Port, 4);
  68.  
  69.                  /* Allocate a session descriptor */
  70.                  sprintf(buffer, "TELNET - %.60s", Host);
  71.                  if ((session = newsession(buffer)) == NULLSESSION)
  72.                  {
  73.                         werr(0, "Too many sessions");
  74.                         return;
  75.                  }
  76.  
  77.                  session->name  = strdup(Host);
  78.                  session->type  = RESOLVING;
  79.                  session->parse = NULLVFP;
  80.  
  81.                  sprintf(buffer, "Resolving %.60s ...\n", Host);
  82.                  Window_Write(session->window, buffer, strlen(buffer));
  83.  
  84.                  resolve_a(Host, Port, NULLCHAR, session, telnet, telnet_error);
  85.         }
  86.  
  87.         dbox_dispose(&d);
  88. }
  89.  
  90. static int telnet_error(char *host, char *message, struct session *s)
  91. {
  92.         char buffer[80];
  93.  
  94.         sprintf(buffer, "Cannot TELNET to %s - %s\n", host, message);
  95.         Window_Write(s->window, buffer, strlen(buffer));
  96.  
  97.         detachsession(s);
  98.  
  99.         return 0; 
  100. }
  101.  
  102. /* Execute user telnet command */
  103. static int telnet(int32 address, char *host, char *port, char *arg2, struct session *s)
  104. {
  105.         char buffer[80];
  106.         struct telnet *tn;
  107.         struct tcb *tcb;
  108.         struct socket lsocket, fsocket;
  109.  
  110.         host = host;
  111.         arg2 = arg2;
  112.  
  113.         lsocket.address = ip_addr;
  114.         lsocket.port    = lport++;
  115.  
  116.         fsocket.address = address;
  117.         fsocket.port    = (atoi(port) > 0) ? atoi(port) : TELNET_PORT;
  118.  
  119.         s->type = TELNET;
  120.         s->addr = fsocket.address;
  121.  
  122.         if ((refuse_echo == 0) && (unix_line_mode != 0))
  123.                 s->parse = unix_send_tel;
  124.         else
  125.                 s->parse = send_tel;
  126.  
  127.         s->echo = 0;
  128.         s->raw  = 1;
  129.  
  130.         /* Create and initialize a Telnet protocol descriptor */
  131.         if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN)
  132.         {
  133.                 Window_Write(s->window, nospace, strlen(nospace));
  134.                 detachsession(s);
  135.                 return 1;
  136.         }
  137.  
  138.         tn->session = s;        /* Upward pointer */
  139.         tn->state = TS_DATA;
  140.         s->cb.telnet = tn;      /* Downward pointer */
  141.  
  142.         sprintf(buffer, "Trying [%s] ...\n", inet_ntoa(address));
  143.         Window_Write(s->window, buffer, strlen(buffer));
  144.  
  145.         tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  146.          (void (*)())rcv_char,(void(*)())tn_tx,(void(*)())t_state,0,(char *)tn);
  147.  
  148.         tn->tcb = tcb;  /* Downward pointer */
  149.  
  150.         return 0;
  151. }
  152.  
  153. /* Process typed characters */
  154. void unix_send_tel(struct session *session, char *buf, int16 n)
  155. {
  156.         int i;
  157.  
  158.         for (i=0; (i<n) && (buf[i] != '\r'); i++)
  159.                 ;
  160.         if (buf[i] == '\r') {
  161.                 buf[i] = '\n';
  162.                 n = i+1;
  163.         }
  164.         send_tel(session, buf,n);
  165. }
  166.  
  167. void send_tel(struct session *session, char *buf, int16 n)
  168. {
  169.         struct mbuf *bp;
  170.  
  171.         if(session->cb.telnet == NULLTN || session->cb.telnet->tcb == NULLTCB)
  172.                 return;
  173.         bp = qdata(buf,n);
  174.         send_tcp(session->cb.telnet->tcb, bp);
  175. }
  176.  
  177. /* Process incoming TELNET characters */
  178. void tel_input(register struct telnet *tn, struct mbuf *bp)
  179. {
  180.         char c;
  181.         register char *s;
  182.         char *line;
  183.  
  184.         if ((line = s = malloc(len_mbuf(bp) + 1)) == NULL)
  185.         {
  186.                 free_p(bp);
  187.                 return;
  188.         }
  189.  
  190.         /* Optimization for very common special case -- no special chars */
  191.         if(tn->state == TS_DATA){
  192.                 while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) == NULLCHAR){
  193.                         while (bp->cnt-- != 0) *s++ = *bp->data++;
  194.                         bp = free_mbuf(bp);
  195.                 }
  196.         }
  197.  
  198.         while (pullup(&bp,&c,1) == 1) {
  199.                 switch(tn->state){
  200.                 case TS_DATA:
  201.                         if(uchar(c) == IAC){
  202.                                 tn->state = TS_IAC;
  203.                         } else {
  204.                                 if(!tn->remote[TN_TRANSMIT_BINARY])
  205.                                         *s++ = c & 0x7f;
  206.                         }
  207.                         break;
  208.                 case TS_IAC:
  209.                         switch(uchar(c)){
  210.                         case WILL:
  211.                                 tn->state = TS_WILL;
  212.                                 break;
  213.                         case WONT:
  214.                                 tn->state = TS_WONT;
  215.                                 break;
  216.                         case DO:
  217.                                 tn->state = TS_DO;
  218.                                 break;
  219.                         case DONT:
  220.                                 tn->state = TS_DONT;
  221.                                 break;
  222.                         case IAC:
  223.                                 Window_Write(tn->session->window, &c, 1);
  224.                                 tn->state = TS_DATA;
  225.                                 break;
  226.                         default:
  227.                                 tn->state = TS_DATA;
  228.                                 break;
  229.                         }
  230.                         break;
  231.                 case TS_WILL:
  232.                         willopt(tn,c);
  233.                         tn->state = TS_DATA;
  234.                         break;
  235.                 case TS_WONT:
  236.                         wontopt(tn,c);
  237.                         tn->state = TS_DATA;
  238.                         break;
  239.                 case TS_DO:
  240.                         doopt(tn,c);
  241.                         tn->state = TS_DATA;
  242.                         break;
  243.                 case TS_DONT:
  244.                         dontopt(tn,c);
  245.                         tn->state = TS_DATA;
  246.                         break;
  247.                 }
  248.         }
  249.         Window_Write(tn->session->window, line, s - line);
  250.         free(line);
  251. }
  252.  
  253. /* Telnet receiver upcall routine */
  254. void rcv_char(register struct tcb *tcb, int16 cnt)
  255. {
  256.         struct mbuf *bp;
  257.         struct telnet *tn;
  258.  
  259.         if((tn = (struct telnet *)tcb->user) == NULLTN){
  260.                 /* Unknown connection; ignore it */
  261.                 return;
  262.         }
  263.  
  264.         if(recv_tcp(tcb,&bp,cnt) > 0)
  265.                 tel_input(tn,bp);
  266. }
  267.  
  268. /* Handle transmit upcalls. Used only for file uploading */
  269. void tn_tx(struct tcb *tcb, int16 cnt)
  270. {
  271.         tcb = tcb;
  272.         cnt = cnt;
  273. }
  274.  
  275. /* State change upcall routine */
  276. void t_state(register struct tcb *tcb, char old, char new)
  277. {
  278.         char buffer[40];
  279.         struct telnet *tn;
  280.         extern char *tcpstates[];
  281.         extern char *reasons[];
  282.         extern char *unreach[];
  283.         extern char *exceed[];
  284.  
  285.         old = old;
  286.  
  287.         /* Can't add a check for unknown connection here, it would loop
  288.          * on a close upcall! We're just careful later on.
  289.          */
  290.         tn = (struct telnet *)tcb->user;
  291.  
  292.         switch(new){
  293.         case CLOSE_WAIT:
  294.                 sprintf(buffer,"%s\n",tcpstates[new]);
  295.                 Window_Write(tn->session->window,buffer,strlen(buffer));
  296.                 close_tcp(tcb);
  297.                 break;
  298.         case CLOSED:    /* court adjourned */
  299.                 sprintf(buffer,"%s (%s",tcpstates[new],reasons[tcb->reason]);
  300.                 Window_Write(tn->session->window,buffer,strlen(buffer));
  301.                 if(tcb->reason == NETWORK){
  302.                         switch(tcb->type){
  303.                         case DEST_UNREACH:
  304.                                 sprintf(buffer,": %s unreachable",unreach[tcb->code]);
  305.                                 Window_Write(tn->session->window,buffer,strlen(buffer));
  306.                                 break;
  307.                         case TIME_EXCEED:
  308.                                 sprintf(buffer,": %s time exceeded",exceed[tcb->code]);
  309.                                 Window_Write(tn->session->window,buffer,strlen(buffer));
  310.                                 break;
  311.                         }
  312.                 }
  313.                 Window_Write(tn->session->window,")\n",2);
  314.                 del_tcp(tcb);
  315.                 if(tn != NULLTN)
  316.                         free_telnet(tn);
  317.                 break;
  318.         default:
  319.                 sprintf(buffer,"%s\n",tcpstates[new]);
  320.                 Window_Write(tn->session->window,buffer,strlen(buffer));
  321.                 break;
  322.         }
  323. }
  324.  
  325. /* Delete telnet structure */
  326. static void free_telnet(struct telnet *tn)
  327. {
  328.         if(tn->session != NULLSESSION)
  329.                 detachsession(tn->session);
  330.  
  331.         if(tn != NULLTN)
  332.                 free((char *)tn);
  333. }
  334.  
  335. /* The guts of the actual Telnet protocol: negotiating options */
  336. static void willopt(struct telnet *tn, char opt)
  337. {
  338.         int ack;
  339.  
  340. #ifdef  DEBUG
  341.         char buffer[80];
  342.  
  343.         if(uchar(opt) <= NOPTIONS)
  344.                 sprintf(buffer,"recv: will %s\n",t_options[opt]);
  345.         else
  346.                 sprintf(buffer,"recv: will %u\n",opt);
  347.         Window_Write(tn->session->window,buffer,strlen(buffer));
  348. #endif
  349.         
  350.         switch(uchar(opt)){
  351.         case TN_TRANSMIT_BINARY:
  352.         case TN_ECHO:
  353.         case TN_SUPPRESS_GA:
  354.                 if(tn->remote[uchar(opt)] == 1)
  355.                         return;         /* Already set, ignore to prevent loop */
  356.                 if(uchar(opt) == TN_ECHO){
  357.                         if(refuse_echo){
  358.                                 /* User doesn't want to accept */
  359.                                 ack = DONT;
  360.                                 break;
  361.                         } else
  362.                                 tn->session->raw = 1;    /* Put tty into raw mode */
  363.                 }
  364.                 tn->remote[uchar(opt)] = 1;
  365.                 ack = DO;                       
  366.                 break;
  367.         default:
  368.                 ack = DONT;     /* We don't know what he's offering; refuse */
  369.         }
  370.         answer(tn,ack,opt);
  371. }
  372. static void wontopt(struct telnet *tn, char opt)
  373. {
  374. #ifdef  DEBUG
  375.         char buffer[80];
  376.  
  377.         if(uchar(opt) <= NOPTIONS)
  378.                 sprintf(buffer,"recv: wont %s\n",t_options[uchar(opt)]);
  379.         else
  380.                 sprintf(buffer,"recv: wont %u\n",uchar(opt));
  381.         Window_Write(tn->session->window,buffer,strlen(buffer));
  382. #endif
  383.         if(uchar(opt) <= NOPTIONS){
  384.                 if(tn->remote[uchar(opt)] == 0)
  385.                         return;         /* Already clear, ignore to prevent loop */
  386.                 tn->remote[uchar(opt)] = 0;
  387.                 if(uchar(opt) == TN_ECHO)
  388.                         tn->session->raw = 0;    /* Put tty into cooked mode */
  389.         }
  390.         answer(tn,DONT,opt);    /* Must always accept */
  391. }
  392. static void doopt(struct telnet *tn, char opt)
  393. {
  394.         int ack;
  395.  
  396. #ifdef  DEBUG
  397.         char buffer[80];
  398.  
  399.         if(uchar(opt) <= NOPTIONS)
  400.                 sprintf(buffer,"recv: do %s\n",t_options[uchar(opt)]);
  401.         else
  402.                 sprintf(buffer,"recv: do %u\n",uchar(opt));
  403.         Window_Write(tn->session->window,buffer,strlen(buffer)); 
  404. #endif
  405.         switch(uchar(opt)){
  406. #ifdef  FUTURE  /* Use when local options are implemented */
  407.                 if(tn->local[uchar(opt)] == 1)
  408.                         return;         /* Already set, ignore to prevent loop */
  409.                 tn->local[uchar(opt)] = 1;
  410.                 ack = WILL;
  411.                 break;
  412. #endif
  413.         default:
  414.                 ack = WONT;     /* Don't know what it is */
  415.         }
  416.         answer(tn,ack,opt);
  417. }
  418. static void dontopt(struct telnet *tn, char opt)
  419. {
  420. #ifdef  DEBUG
  421.         char buffer[80]; 
  422.  
  423.         if(uchar(opt) <= NOPTIONS)
  424.                 sprintf(buffer,"recv: dont %s\n",t_options[uchar(opt)]);
  425.         else
  426.                 sprintf(buffer,"recv: dont %u\n",uchar(opt));
  427.         Window_Write(tn->session->window,buffer,strlen(buffer));
  428. #endif
  429.         if(uchar(opt) <= NOPTIONS){
  430.                 if(tn->local[uchar(opt)] == 0){
  431.                         /* Already clear, ignore to prevent loop */
  432.                         return;
  433.                 }
  434.                 tn->local[uchar(opt)] = 0;
  435.         }
  436.         answer(tn,WONT,opt);
  437. }
  438. static void answer(struct telnet *tn, int r1, int r2)
  439. {
  440.         struct mbuf *bp;
  441.         char s[3];
  442.  
  443. #ifdef  DEBUG
  444.         switch(r1){
  445.         case WILL:
  446.                 cwprintf("sent: will ");
  447.                 break;
  448.         case WONT:
  449.                 cwprintf("sent: wont ");
  450.                 break;
  451.         case DO:
  452.                 cwprintf("sent: do ");
  453.                 break;
  454.         case DONT:
  455.                 cwprintf("sent: dont ");
  456.                 break;
  457.         }
  458.         if(r2 <= 6)
  459.                 cwprintf("%s\n",t_options[r2]);
  460.         else
  461.                 cwprintf("%u\n",r2);
  462. #endif
  463.  
  464.         s[0] = IAC;
  465.         s[1] = r1;
  466.         s[2] = r2;
  467.         bp = qdata(s,(int16)3);
  468.         send_tcp(tn->tcb,bp);
  469. }
  470.